package com.sample.springbatch.scheduling.service;

import com.sample.springbatch.common.MyPage;
import com.sample.springbatch.job.service.BatchJobService;
import com.sample.springbatch.scheduling.model.QuartzExecution;
import com.sample.springbatch.scheduling.model.QuartzInfo;
import com.sample.springbatch.scheduling.model.QuartzJobInfo;
import com.sample.springbatch.scheduling.repository.QuartzExecutionRepository;
import com.sample.springbatch.scheduling.repository.QuartzInfoRepository;
import com.sample.springbatch.scheduling.repository.QuartzJobInfoRepository;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;

/**
 * 定时任务管理服务类
 * Created by zwg on 2017/9/11.
 */
@Service
public class QuartzMgrService {

    public static final Logger logger = LoggerFactory.getLogger(QuartzMgrService.class);

    @Autowired
    SchedulerFactoryBean schedulerFactoryBean;
    @Autowired
    BatchJobService batchJobService;
    @Autowired
    QuartzInfoRepository quartzInfoRepository;
    @Autowired
    QuartzExecutionRepository quartzLogRepository;
    @Autowired
    QuartzJobInfoRepository quartzJobInfoRepository;

    /**
     * 获取所有的定时任务信息
     * @return
     */
    public List<QuartzInfo> getQuartzInfoList(int status){

        List<QuartzInfo> quartzInfoList = quartzInfoRepository.findByStatusOrderByIdDesc(status);

        return quartzInfoList;
    }

    /**
     * 获定时任务日志
     * @param pageNo
     * @param pageSize
     * @return
     */
    public MyPage<QuartzExecution> getQuartzLogPage(int quartzId, int pageNo, int pageSize){
        return null;
    }

    /**
     * 获取定时任务的作业列表
     * @param quartzId
     * @return
     */
    public List<QuartzJobInfo> getQuartzJobInfoList(int quartzId, boolean hasTriggerState){
        List<QuartzJobInfo> quartzJobInfoList = quartzJobInfoRepository.findByQuartzIdAndStatus(quartzId,1);
        if(quartzJobInfoList!=null && !quartzJobInfoList.isEmpty() && hasTriggerState){
            try{
                Scheduler scheduler = schedulerFactoryBean.getScheduler();
                for (QuartzJobInfo job: quartzJobInfoList) {
                    Trigger.TriggerState ts = scheduler.getTriggerState(TriggerKey.triggerKey(getQuartzJobKey(job.getName())));
                    job.setTriggerState(ts.toString());
                }
            }catch (SchedulerException e){
                logger.error("getQuartzJobInfoList 获取 trigger state 错误。");
            }

        }
        return quartzJobInfoList;
    }


    @PostConstruct()
    public void loadQuartz() throws SchedulerException {
        List<QuartzInfo> quartzInfoList = quartzInfoRepository.findByStatusOrderByIdDesc(1);
        if(quartzInfoList==null || quartzInfoList.isEmpty()){
            logger.info("server init no quartz info.");
        }
        for (QuartzInfo quartzInfo : quartzInfoList) {
            //TODO 验证 q
            if(!StringUtils.isEmpty(quartzInfo.getDependHost())){

            }
            //加载作业
            this.loadQuartzJobs(quartzInfo.getId(),false);
        }
    }


    public void loadQuartzJobs(int quartzId, boolean startTrigger) throws SchedulerException{
        //运行状态的job
        List<QuartzJobInfo> quartzJobInfoList = quartzJobInfoRepository.findByQuartzIdAndStatus(quartzId,1);
        if(quartzJobInfoList==null || quartzJobInfoList.isEmpty()){
            logger.info("loadQuartzJobs  no quartz job.");
        }
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        StringBuffer logBuff = new StringBuffer(" load quartz jobs "+quartzJobInfoList.size()+" 个: ");
        for (QuartzJobInfo job : quartzJobInfoList) {
            String quartzTriggerKey = getQuartzJobKey(job.getName());
            TriggerKey triggerKey = TriggerKey.triggerKey(quartzTriggerKey);

            //获取trigger，不存在创建，存在修改
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            //不存在，创建一个
            if (null == trigger) {
                JobDetail jobDetail = JobBuilder.newJob(BatchJobFactory.class)
                        .withIdentity(quartzTriggerKey).build();
                jobDetail.getJobDataMap().put("jobInfo", job);
                jobDetail.getJobDataMap().put("jobService", batchJobService);

                //表达式调度构建器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job
                        .getCronExpression());

                //按新的cronExpression表达式构建一个新的trigger
                trigger = TriggerBuilder.newTrigger().withIdentity(quartzTriggerKey).withSchedule(scheduleBuilder).build();

                scheduler.scheduleJob(jobDetail, trigger);
                //默认暂停触发器  当前指定全部启动或默认启动的时候才启动
                if(!startTrigger && job.getTriggerInitStatus()!=1){
                    scheduler.pauseJob(jobDetail.getKey());
                }

                logBuff.append("add [").append(job.getName()).append("][").append(job.getCronExpression()).append("]|");
            } else {
                // Trigger已存在，那么更新相应的定时设置
                //表达式调度构建器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job
                        .getCronExpression());

                //按新的cronExpression表达式重新构建trigger
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                        .withSchedule(scheduleBuilder).build();

                //按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
                //默认暂停触发器  当前指定全部启动或默认启动的时候才启动
                if(!startTrigger && job.getTriggerInitStatus()!=1) {
                    scheduler.pauseJob(trigger.getJobKey());
                }
                logBuff.append("update [").append(job.getName()).append("][").append(job.getCronExpression()).append("]|");
            }
        }
        logger.info(logBuff.toString());
    }

    /**
     * 启动批量作业
     * 1. 记录quartzLog
     * 2. 加载QuartzJobs
     * @param quartzId
     */
    public void startQuartz(int quartzId) throws SchedulerException{
        QuartzInfo quartzInfo = quartzInfoRepository.findOne(quartzId);
        if(quartzInfo==null){
            logger.error("需要启动的批量作业定时任务不存在,quartzId:{}",quartzId);
        }
        if(quartzInfo.getStatus()!=1){
            logger.error("需要启动的批量作业定时任务状态错误,quartz info:{}",quartzId,quartzInfo.toString());
        }

        //保存
        QuartzExecution quartzLog = new QuartzExecution();
        quartzLog.setQuartzId(quartzId);
        quartzLog.setStatus(0); //运行
        quartzLog.setCreateTime(new Date());
        quartzLog.setUpdateTime(new Date());
        quartzLogRepository.save(quartzLog);
    }

    /**
     * 暂停定时任务
     * @param job
     * @return
     * @throws SchedulerException
     */
    public QuartzJobInfo pauseCron(QuartzJobInfo job) throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobKey jobKey = JobKey.jobKey(getQuartzJobKey(job.getName()));
        scheduler.pauseJob(jobKey);

        job.setTriggerState(Trigger.TriggerState.PAUSED.name());
        return job;
    }

    private static String getQuartzJobKey(String jobName){
        return "job_"+jobName;
    }


    /**
     * 恢复定时任务
     * @param job
     * @return
     * @throws SchedulerException
     */
    public QuartzJobInfo resumeCron(QuartzJobInfo job) throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobKey jobKey = JobKey.jobKey(getQuartzJobKey(job.getName()));
        scheduler.resumeJob(jobKey);

        job.setTriggerState(Trigger.TriggerState.NORMAL.name());
        return job;
    }

}
